/**
 * 
 */
package co.fitstart.market.web.controller.auth;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import com.demo2do.core.support.Result;
import com.demo2do.core.web.handler.CookieHandler;
import com.demo2do.core.web.utils.WebUtils;
import com.demo2do.core.wechat.authorization.AuthorizationScope;
import com.demo2do.core.wechat.authorization.handler.AppAuthHandler;
import com.demo2do.core.wechat.support.AppType;

import co.fitstart.entity.user.UserAccount;
import co.fitstart.entity.user.WechatAccount;
import co.fitstart.market.Constant;
import co.fitstart.market.service.UserService;

/**
 * @author lute
 *
 */
@Controller
@RequestMapping("")
public class WechatInfoAuthController {

    private static final Logger logger = LoggerFactory.getLogger(WechatInfoAuthController.class);
    
    private static final String SAVED_REQUEST = "WECHAT_WEB_AUTHORITY_SAVED_REQUEST";
    
    @Autowired
    private CookieHandler cookieHandler;
    
    @Autowired
    private AppAuthHandler appAuthHandler;
    
    @Autowired
    private UserService userService;
    
    /**
     * Prepare WeChat user info scoped authorization code URL and redirect to it
     * 
     * @param httpServletRequest
     * @return
     */
    @RequestMapping("/wx/pre-auth")
    public String preAuthorization(HttpServletRequest httpServletRequest) {
        String serverRealPath = WebUtils.getRealServerPath(httpServletRequest);
        String codeUrl = appAuthHandler.generateCodeUrl(serverRealPath + "/wx/post-auth", AuthorizationScope.USERINFO, AppType.OFFICIAL, null);
        return "redirect:" + codeUrl;
    }
    
    /**
     * Receive code from WeChat user info scoped authorization and exchange
     * openid, access token with code
     * 
     * @param code
     * @param state
     * @param httpServletResponse
     * @param httpSession
     * @return
     */
    @RequestMapping("/wx/post-auth")
    public ModelAndView onPostAuthorization(@RequestParam(value = "code", required = false) String code,
                                            @RequestParam(value = "state", required = false) String state,
                                            HttpServletResponse httpServletResponse,
                                            HttpSession httpSession) {
        
        ModelAndView modelAndView = new ModelAndView();
        
        // Gets saved request from http session
        String originalUrl = (String) httpSession.getAttribute(SAVED_REQUEST);
        
        // If code returned from wechat is not empty, then goes to retrieve openid using code
        if (StringUtils.isNotBlank(code)) {
            
            // get access token first
            Result authResult = appAuthHandler.exchangeAccessToken(code, AppType.OFFICIAL);
            
            if (authResult.isValid()) {
                
                // Extract openid, access token and expires time
                String openid = (String) authResult.get("openid");
                String accessToken = (String) authResult.get("access_token");
                int expireTime = ((Integer) authResult.get("expires_in")).intValue();
                
                logger.trace("WechatAuthorizationController#onPostAuthorization() - Get openid [{}], access token [{}] and expires time [{}].", openid, accessToken, expireTime);
                
                if (StringUtils.isNotBlank(openid)) {
                    
                    try {
                        
                        // create new user account if not exit
                        UserAccount userAccount = userService.getUserAccount(Constant.USER_ACCOUNT_WECHAT_KEY, openid);
                        
                        if(userAccount == null) {
                            
                            // Request wechat user information
                            Result userInfoResult = appAuthHandler.requestUserInfo(accessToken, openid, false);
                            
                            // create & save userAccount & wechatAccount
                            userAccount = new UserAccount(Constant.USER_ACCOUNT_WECHAT_KEY, openid);
                            WechatAccount wechatAccount = new WechatAccount(userInfoResult.getData());
                            
                            userService.createUserAccount(userAccount, wechatAccount);
                        }
                        
                        // Add openid and accountid and access token into cookie
                        String accountId = String.valueOf(userAccount.getId());
                        
                        cookieHandler.addCookie(httpServletResponse, Constant.OPENID_KEY, openid, expireTime);
                        cookieHandler.addCookie(httpServletResponse, Constant.USER_ACCOUNT_KEY, accountId, expireTime);
                        
                    } catch (Exception e) {
                        
                        logger.trace("AuthorizationController#onPostUserInfoAuthorization() - Authorizing user encounters exception: [{}]", e);
                        
                        modelAndView.setViewName("auth-error");
                        
                        return modelAndView;
                    }
                    
                    // If original URL is not empty, redirect to original URL. Or redirect to root path.
                    if (StringUtils.isNotBlank(originalUrl)) {
                        modelAndView.setViewName("redirect:" + originalUrl);
                    } else {
                        modelAndView.setViewName("redirect:/");
                    }
                    
                    return modelAndView;
                }
                
            } else {
                
                modelAndView.addObject("errmsg", authResult.get("errmsg"));
            
            }
            
        } else {
            
            logger.error("WechatAuthorizationController#onPostAuthorization() - Requesting WeChat code occurs unknown errors. No code returned from WeChat.");
        
        }
        
        return modelAndView;
    }
    
    /**
     * 
     * @return
     */
    @RequestMapping(value = "/wx/auth-error", method = RequestMethod.GET)
    public String authorizeError() {
        return "auth/wx-auth-error";
    }
    
    /**
     * 
     * @return
     */
    @RequestMapping(value = "/required-landing", method = RequestMethod.GET)
    public String requiredLanding() {
        return "auth/require-wechat-landing";
    }

}
